home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_01 / ex.c < prev    next >
C/C++ Source or Header  |  1992-04-04  |  17KB  |  723 lines

  1. /* ex.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the code for reading ex commands. */
  12.  
  13. #include "config.h"
  14. #include "ctype.h"
  15. #include "vi.h"
  16.  
  17. /* This data type is used to describe the possible argument combinations */
  18. typedef short ARGT;
  19. #define FROM    1        /* allow a linespec */
  20. #define    TO    2        /* allow a second linespec */
  21. #define BANG    4        /* allow a ! after the command name */
  22. #define EXTRA    8        /* allow extra args after command name */
  23. #define XFILE    16        /* expand wildcards in extra part */
  24. #define NOSPC    32        /* no spaces allowed in the extra part */
  25. #define    DFLALL    64        /* default file range is 1,$ */
  26. #define DFLNONE    128        /* no default file range */
  27. #define NODFL    256        /* do not default to the current file name */
  28. #define EXRCOK    512        /* can be in a .exrc file */
  29. #define NL    1024        /* if mode!=MODE_EX, then write a newline first */
  30. #define PLUS    2048        /* allow a line number, as in ":e +32 foo" */
  31. #define ZERO    4096        /* allow 0 to be given as a line number */
  32. #define NOBAR    8192        /* treat following '|' chars as normal */
  33. #define FILES    (XFILE + EXTRA)    /* multiple extra files allowed */
  34. #define WORD1    (EXTRA + NOSPC)    /* one extra word allowed */
  35. #define FILE1    (FILES + NOSPC)    /* 1 file allowed, defaults to current file */
  36. #define NAMEDF    (FILE1 + NODFL)    /* 1 file allowed, defaults to "" */
  37. #define NAMEDFS    (FILES + NODFL)    /* multiple files allowed, default is "" */
  38. #define RANGE    (FROM + TO)    /* range of linespecs allowed */
  39. #define NONE    0        /* no args allowed at all */
  40.  
  41. /* This array maps ex command names to command codes. The order in which
  42.  * command names are listed below is significant -- ambiguous abbreviations
  43.  * are always resolved to be the first possible match.  (e.g. "r" is taken
  44.  * to mean "read", not "rewind", because "read" comes before "rewind")
  45.  */
  46. static struct
  47. {
  48.     char    *name;    /* name of the command */
  49.     CMD    code;    /* enum code of the command */
  50.     void    (*fn)();/* function which executes the command */
  51.     ARGT    argt;    /* command line arguments permitted/needed/used */
  52. }
  53.     cmdnames[] =
  54. {   /*    cmd name    cmd code    function    arguments */
  55.     {"append",    CMD_APPEND,    cmd_append,    FROM+ZERO+BANG    },
  56. #ifdef DEBUG
  57.     {"bug",        CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  58. #endif
  59.     {"change",    CMD_CHANGE,    cmd_append,    RANGE+BANG    },
  60.     {"delete",    CMD_DELETE,    cmd_delete,    RANGE+WORD1    },
  61.     {"edit",    CMD_EDIT,    cmd_edit,    BANG+FILE1+PLUS    },
  62.     {"file",    CMD_FILE,    cmd_file,    NAMEDF        },
  63.     {"global",    CMD_GLOBAL,    cmd_global,    RANGE+BANG+EXTRA+DFLALL+NOBAR},
  64.     {"insert",    CMD_INSERT,    cmd_append,    FROM+BANG    },
  65.     {"join",    CMD_INSERT,    cmd_join,    RANGE+BANG    },
  66.     {"k",        CMD_MARK,    cmd_mark,    FROM+WORD1    },
  67.     {"list",    CMD_LIST,    cmd_print,    RANGE+NL    },
  68.     {"move",    CMD_MOVE,    cmd_move,    RANGE+EXTRA    },
  69.     {"next",    CMD_NEXT,    cmd_next,    BANG+NAMEDFS    },
  70.     {"Next",    CMD_PREVIOUS,    cmd_next,    BANG        },
  71.     {"print",    CMD_PRINT,    cmd_print,    RANGE+NL    },
  72.     {"quit",    CMD_QUIT,    cmd_xit,    BANG        },
  73.     {"read",    CMD_READ,    cmd_read,    FROM+ZERO+NAMEDF},
  74.     {"substitute",    CMD_SUBSTITUTE,    cmd_substitute,    RANGE+EXTRA    },
  75.     {"to",        CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  76.     {"undo",    CMD_UNDO,    cmd_undo,    NONE        },
  77.     {"vglobal",    CMD_VGLOBAL,    cmd_global,    RANGE+EXTRA+DFLALL+NOBAR},
  78.     {"write",    CMD_WRITE,    cmd_write,    RANGE+BANG+FILE1+DFLALL},
  79.     {"xit",        CMD_XIT,    cmd_xit,    BANG+NL        },
  80.     {"yank",    CMD_YANK,    cmd_delete,    RANGE+WORD1    },
  81.  
  82.     {"!",        CMD_BANG,    cmd_shell,    EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR},
  83.     {"#",        CMD_NUMBER,    cmd_print,    RANGE+NL    },
  84.     {"<",        CMD_SHIFTL,    cmd_shift,    RANGE        },
  85.     {">",        CMD_SHIFTR,    cmd_shift,    RANGE        },
  86.     {"=",        CMD_EQUAL,    cmd_file,    RANGE        },
  87.     {"&",        CMD_SUBAGAIN,    cmd_substitute,    RANGE        },
  88. #ifndef NO_AT
  89.     {"@",        CMD_AT,        cmd_at,        EXTRA        },
  90. #endif
  91.  
  92. #ifndef NO_ABBR
  93.     {"abbreviate",    CMD_ABBR,    cmd_map,    EXRCOK+BANG+EXTRA},
  94. #endif
  95.     {"args",    CMD_ARGS,    cmd_args,    EXRCOK+NAMEDFS    },
  96. #ifndef NO_ERRLIST
  97.     {"cc",        CMD_CC,        cmd_make,    BANG+FILES    },
  98. #endif
  99.     {"cd",        CMD_CD,        cmd_cd,        EXRCOK+BANG+NAMEDF},
  100.     {"copy",    CMD_COPY,    cmd_move,    RANGE+EXTRA    },
  101. #ifndef NO_DIGRAPH
  102.     {"digraph",    CMD_DIGRAPH,    cmd_digraph,    EXRCOK+BANG+EXTRA},
  103. #endif
  104. #ifndef NO_ERRLIST
  105.     {"errlist",    CMD_ERRLIST,    cmd_errlist,    BANG+NAMEDF    },
  106. #endif
  107.     {"ex",        CMD_EDIT,    cmd_edit,    BANG+FILE1    },
  108.     {"mark",    CMD_MARK,    cmd_mark,    FROM+WORD1    },
  109. #ifndef NO_MKEXRC
  110.     {"mkexrc",    CMD_MKEXRC,    cmd_mkexrc,    NAMEDF        },
  111. #endif
  112.     {"number",    CMD_NUMBER,    cmd_print,    RANGE+NL    },
  113.     {"put",        CMD_PUT,    cmd_put,    FROM+ZERO+WORD1    },
  114.     {"set",        CMD_SET,    cmd_set,    EXRCOK+EXTRA    },
  115.     {"shell",    CMD_SHELL,    cmd_shell,    NL        },
  116.     {"source",    CMD_SOURCE,    cmd_source,    EXRCOK+NAMEDF    },
  117. #ifdef SIGTSTP
  118.     {"stop",    CMD_STOP,    cmd_suspend,    NONE        },
  119. #endif
  120.     {"tag",        CMD_TAG,    cmd_tag,    BANG+WORD1    },
  121.     {"version",    CMD_VERSION,    cmd_version,    EXRCOK+NONE    },
  122.     {"visual",    CMD_VISUAL,    cmd_edit,    BANG+NAMEDF    },
  123.     {"wq",        CMD_WQUIT,    cmd_xit,    NL        },
  124.  
  125. #ifdef DEBUG
  126.     {"debug",    CMD_DEBUG,    cmd_debug,    RANGE+BANG+EXTRA+NL},
  127.     {"validate",    CMD_VALIDATE,    cmd_validate,    BANG+NL        },
  128. #endif
  129.     {"chdir",    CMD_CD,        cmd_cd,        EXRCOK+BANG+NAMEDF},
  130. #ifndef NO_COLOR
  131.     {"color",    CMD_COLOR,    cmd_color,    EXRCOK+EXTRA    },
  132. #endif
  133. #ifndef NO_ERRLIST
  134.     {"make",    CMD_MAKE,    cmd_make,    BANG+NAMEDFS    },
  135. #endif
  136.     {"map",        CMD_MAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  137.     {"previous",    CMD_PREVIOUS,    cmd_next,    BANG        },
  138.     {"rewind",    CMD_REWIND,    cmd_next,    BANG        },
  139. #ifdef SIGTSTP
  140.     {"suspend",    CMD_SUSPEND,    cmd_suspend,    NONE        },
  141. #endif
  142.     {"unmap",    CMD_UNMAP,    cmd_map,    EXRCOK+BANG+EXTRA},
  143. #ifndef NO_ABBR
  144.     {"unabbreviate",CMD_UNABBR,    cmd_map,    EXRCOK+WORD1    },
  145. #endif
  146.  
  147.     {(char *)0}
  148. };
  149.  
  150.  
  151. /* This function parses a search pattern - given a pointer to a / or ?,
  152.  * it replaces the ending / or ? with a \0, and returns a pointer to the
  153.  * stuff that came after the pattern.
  154.  */
  155. char    *parseptrn(ptrn)
  156.     REG char    *ptrn;
  157. {
  158.     REG char     *scan;
  159.  
  160.     for (scan = ptrn + 1;
  161.          *scan && *scan != *ptrn;
  162.          scan++)
  163.     {
  164.         /* allow backslashed versions of / and ? in the pattern */
  165.         if (*scan == '\\' && scan[1] != '\0')
  166.         {
  167.             scan++;
  168.         }
  169.     }
  170.     if (*scan)
  171.     {
  172.         *scan++ = '\0';
  173.     }
  174.  
  175.     return scan;
  176. }
  177.  
  178.  
  179. /* This function parses a line specifier for ex commands */
  180. char *linespec(s, markptr)
  181.     REG char    *s;        /* start of the line specifier */
  182.     MARK        *markptr;    /* where to store the mark's value */
  183. {
  184.     long        num;
  185.     REG char    *t;
  186.  
  187.     /* parse each ;-delimited clause of this linespec */
  188.     do
  189.     {
  190.         /* skip an initial ';', if any */
  191.         if (*s == ';')
  192.         {
  193.             s++;
  194.         }
  195.  
  196.         /* skip leading spaces */
  197.         while (isspace(*s))
  198.         {
  199.             s++;
  200.         }
  201.  
  202.         /* dot means current position */
  203.         if (*s == '.')
  204.         {
  205.             s++;
  206.             *markptr = cursor;
  207.         }
  208.         /* '$' means the last line */
  209.         else if (*s == '$')
  210.         {
  211.             s++;
  212.             *markptr = MARK_LAST;
  213.         }
  214.         /* digit means an absolute line number */
  215.         else if (isdigit(*s))
  216.         {
  217.             for (num = 0; isdigit(*s); s++)
  218.             {
  219.                 num = num * 10 + *s - '0';
  220.             }
  221.             *markptr = MARK_AT_LINE(num);
  222.         }
  223.         /* appostrophe means go to a set mark */
  224.         else if (*s == '\'')
  225.         {
  226.             s++;
  227.             *markptr = m_tomark(cursor, 1L, (int)*s);
  228.             s++;
  229.         }
  230.         /* slash means do a search */
  231.         else if (*s == '/' || *s == '?')
  232.         {
  233.             /* put a '\0' at the end of the search pattern */
  234.             t = parseptrn(s);
  235.  
  236.             /* search for the pattern */
  237.             *markptr &= ~(BLKSIZE - 1);
  238.             if (*s == '/')
  239.             {
  240.                 pfetch(markline(*markptr));
  241.                 if (plen > 0)
  242.                     *markptr += plen - 1;
  243.                 *markptr = m_fsrch(*markptr, s);
  244.             }
  245.             else
  246.             {
  247.                 *markptr = m_bsrch(*markptr, s);
  248.             }
  249.  
  250.             /* adjust command string pointer */
  251.             s = t;
  252.         }
  253.  
  254.         /* if linespec was faulty, quit now */
  255.         if (!*markptr)
  256.         {
  257.             return s;
  258.         }
  259.  
  260.         /* maybe add an offset */
  261.         t = s;
  262.         if (*t == '-' || *t == '+')
  263.         {
  264.             s++;
  265.             for (num = 0; isdigit(*s); s++)
  266.             {
  267.                 num = num * 10 + *s - '0';
  268.             }
  269.             if (num == 0)
  270.             {
  271.                 num = 1;
  272.             }
  273.             *markptr = m_updnto(*markptr, num, *t);
  274.         }
  275.     } while (*s == ';' || *s == '+' || *s == '-');
  276.  
  277.     /* protect against invalid line numbers */
  278.     num = markline(*markptr);
  279.     if (num < 1L || num > nlines)
  280.     {
  281.         msg("Invalid line number -- must be from 1 to %ld", nlines);
  282.         *markptr = MARK_UNSET;
  283.     }
  284.  
  285.     return s;
  286. }
  287.  
  288.  
  289.